package com.kaede.game;

import java.net.InetSocketAddress;

import com.kaede.game.config.GameConfig;
import com.kaede.game.dto.CommonRequestOuterClass;
import com.kaede.game.netty.ProtoBufInitializer;
import com.kaede.game.netty.ServerHandler;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.boot.context.properties.EnableConfigurationProperties;

import javax.annotation.PreDestroy;

@SpringBootApplication
@EnableConfigurationProperties(GameConfig.class)
public class GameApplication implements CommandLineRunner{

	protected Logger logger = LoggerFactory.getLogger(getClass());

	@Autowired
	private GameConfig gameConfig;

	@Autowired
	private ServerHandler serverHandler;

	private Channel serverChannel;

	public static void main(String[] args) {
		SpringApplication.run(GameApplication.class, args);
	}

	@PreDestroy
	private void shutdownServer(){
	    if(serverChannel != null){
            serverChannel.close();
        }
    }

	@Override
	public void run(String... args) throws Exception {

		//(1) 创建EventLoopGroup
        NioEventLoopGroup bossGroup = new NioEventLoopGroup(); // (1)
        NioEventLoopGroup workerGroup = new NioEventLoopGroup();
		try {
			//(2) 创建ServerBootstrap
			ServerBootstrap b = new ServerBootstrap();
			b.group(bossGroup, workerGroup)
					//(3) 指定所使用的 NIO 传输 Channel
					.channel(NioServerSocketChannel.class)
					//(4) 使用指定的端口设置套接字地址
					.localAddress(new InetSocketAddress(gameConfig.getPort()))
					//(5) 添加一个EchoServerHandler到于Channel的 ChannelPipeline
					.childHandler(new ProtoBufInitializer(serverHandler, CommonRequestOuterClass.CommonRequest.getDefaultInstance(), gameConfig.getMaxFrameLength(),
                            gameConfig.getLengthFieldOffset(), gameConfig.getLengthFieldLength(), gameConfig.getLengthAdjustment(), gameConfig.getInitialBytesToStrip()));
			//(6) 异步地绑定服务器；调用 sync()方法阻塞等待直到绑定完成
			ChannelFuture f = b.bind().sync();
            //(7) 获取 Channel 的CloseFuture，并且阻塞当前线程直到它完成
            serverChannel = f.channel();
            logger.info(GameApplication.class.getName() + " started and listening for connections on " + serverChannel.localAddress());
            serverChannel.closeFuture().sync();
		} finally {
			//(8) 关闭 EventLoopGroup，释放所有的资源
			bossGroup.shutdownGracefully().sync();
			workerGroup.shutdownGracefully().sync();
		}
	}

    public Channel getServerChannel() {
        return serverChannel;
    }

    public void setServerChannel(Channel serverChannel) {
        this.serverChannel = serverChannel;
    }
}
